import java.awt.*;
import java.util.ArrayList;

import com.speljohan.rsbot.bot.Bot;
import com.speljohan.rsbot.event.listeners.PaintListener;
import com.speljohan.rsbot.script.Script;
import com.speljohan.rsbot.script.wrappers.*;

public class FlaxSpinner extends Script implements PaintListener { // Declaring
	// name
	// +
	// saying
	// it's
	// a
	// script
	// (filename
	// should
	// be
	// same
	// as
	// the
	// part
	// between
	// class
	// and
	// extends
	// eg.
	// ScriptBase.java)
	public boolean onStart(String[] args) {
		stringsBanked = 0;
		startTime = System.currentTimeMillis();
		proggy = true;
		
		return true;
	}

	public void onFinish() {
		Bot.getEventManager().removeListener(PaintListener.class, this);
		proggy = false;
	}

	public String getName() { // Name of the Script
		return "Flax Spinner"; // between "" what will show up in RSBot
		// script selector
	}

	public String getAuthor() {
		return "Mike";
	}

	public double getVersion() {
		return 1.0;
	}

	Color BG = new Color(123, 123, 123, 100);
	Color GREEN = new Color(0, 255, 0, 255);
	Color RED = new Color(255, 0, 0, 255);
	long startTime = System.currentTimeMillis();
	boolean proggy = false;
	RSTile bankTile = new RSTile(2725, 3491);
	RSTile outsideTile = new RSTile(2717, 3471);
	int LADDER_UP_ID = 25938;
	int LADDER_DOWN_ID = 25939;
	int SPINNING_WHEEL_ID = 25824;
	int FLAX_ID = 1779;
	int BOW_STRING_ID = 1777;
	int STRINGING_INTERFACE_ID = 459;
	int BOW_STRING_CHILD_ID = 17;
	RSTile DOOR_CLOSE_TILE = new RSTile(2716, 3472);
	int stringsBanked = 0;

	public int loop() {
		try {
			if (getMyPlayer().isMoving() && distanceTo(getFlag()) > 1) {
				return random(100, 200);
			}
			int height = getPlane();
			if (height == 0) {
				if (getEnergy() > random(50, 99)) {
					setRun(true);
				}
			}
			if (getInventoryCount(FLAX_ID) == 0 || getMyPlayer().isInCombat()) {
				if (RSInterface.getInterface(STRINGING_INTERFACE_ID).isValid()) {
					atInterface(STRINGING_INTERFACE_ID, 12);
				}
				if (height == 1) {
					RSObject ladder = findObject(LADDER_DOWN_ID);
					if (ladder == null) {
						return random(100, 200);
					}
					if (!atObject(ladder, "Climb-down")) {
						turnToTile(ladder.getLocation());
					}
					return random(500, 700);
				}
				if (height == 0) {
					if (bank.getInterface().isValid()) {
						int strings = getInventoryCount(BOW_STRING_ID);
						if (bank.depositAllExcept(FLAX_ID)) {
							stringsBanked += strings;
							clickMouse(random(38, 74), random(92, 124), false);
							atMenu("Withdraw-All");
						}
						return random(100, 200);
					}
					RSObject bankObj = findObject(25808);
					if (bankObj == null || !tileOnScreen(bankObj.getLocation())) {
						RSObject door = getObjectAt(DOOR_CLOSE_TILE);
						if (door != null && distanceTo(door) < 3
								&& getObjectAt(door.getLocation()) != null) {
							if (!atDoor(door, "West", "Open")) {
								turnToTile(door.getLocation());
								return random(500, 700);
							}
						}
						walkPathMM(randomizePath(generatePath(bankTile), 2, 2),
								17);
					} else if (bankObj != null) {
						if (!atObject(bankObj, "Use-quickly")) {
							turnToTile(bankObj.getLocation());
						}
					}
				}
			}
			if (getInventoryCount(FLAX_ID) > 0) {
				if (height == 0) {
					RSObject door = getObjectAt(DOOR_CLOSE_TILE);
					if (door != null && distanceTo(door) < 7) {
						if (!atDoor(door, "West", "Open")) {
							turnToTile(door.getLocation());
							return random(50, 100);
						} else {
							return random(500, 700);
						}
					}
					if (walkPathMM(randomizePath(generatePath(outsideTile), 2,
							2), 17)) {
						RSObject ladder = findObject(LADDER_UP_ID);
						if (ladder != null) {
							if (!atObject(ladder, "Climb-up")) {
								turnToTile(ladder.getLocation());
							} else {
								return random(500, 700);
							}
						}
						return random(100, 200);
					}
				}
				if (height == 1) {
					for (int i = 0; i != 10; i++) {
						if (getMyPlayer().getAnimation() != -1
								&& !getMyPlayer().isInCombat()) {
							return random(100, 200);
						} else {
							wait(random(100, 200));
						}
					}
					if (RSInterface.getInterface(STRINGING_INTERFACE_ID)
							.isValid()) {
						atInterface(STRINGING_INTERFACE_ID,
								BOW_STRING_CHILD_ID, "all");
						return random(500, 1000);
					}
					RSObject spinningWheel = findObject(SPINNING_WHEEL_ID);
					if (spinningWheel == null) {
						return random(100, 200);
					}
					if (!atObject(spinningWheel, "Spin")) {
						turnToTile(spinningWheel.getLocation());
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return random(100, 200); // Time to restart the loop method, advised
		// to be random; return -1 = Stop Script
	}

	public int getAngleToCoordinates(int x2, int y2) {
		int x1 = getMyPlayer().getLocation().getX();
		int y1 = getMyPlayer().getLocation().getY();
		int x = x1 - x2;
		int y = y1 - y2;
		double angle = Math.toDegrees(Math.atan2(x, y));
		if (x == 0 && y > 0) {
			angle = 180;
		}
		if (x < 0 && y == 0) {
			angle = 90;
		}
		if (x == 0 && y < 0) {
			angle = 0;
		}
		if (x < 0 && y == 0) {
			angle = 270;
		}
		if (x < 0 && y > 0) {
			angle += 270;
		}
		if (x > 0 && y > 0) {
			angle += 90;
		}
		if (x < 0 && y < 0) {
			angle = Math.abs(angle) - 180;
		}
		if (x > 0 && y < 0) {
			angle = Math.abs(angle) + 270;
		}
		if (angle < 0) {
			angle = 360 + angle;
		}
		if (angle >= 360) {
			angle -= 360;
		}
		return (int) angle;
	}

	public void turnToTile(RSTile tile) {
		int angle = getAngleToCoordinates(tile.getX(), tile.getY());
		angle = angle + random(-20, 20);
		if (angle < 0) {
			angle = 360 + angle;
		}
		if (angle >= 360) {
			angle -= 360;
		}
		setCameraRotation2(angle);
	}

	public String getScriptDescription() {
		return "<html>"
				+ "Start the script in <u><b>Seers village</b></u>... <br>Flax in <b>first bank spot</b>. <br>It can start <b>anywhere</b> in the process of spinning."
				+ "</html>";
	}

	public String getScriptCategory() {
		return "Crafting";
	}

	public RSTile getFlag() {
		if (Bot.getClient().getDestX() > 0) {
			return new RSTile(Bot.getClient().getDestX()
					+ Bot.getClient().getBaseX(), Bot.getClient().getDestY()
					+ Bot.getClient().getBaseY());
		}
		return null;
	}

	public void onRepaint(Graphics g) { // stole transparent box from ~alex~'s
		// AlFlax
		if (isLoggedIn() && proggy == true) {
			long millis = System.currentTimeMillis() - startTime;
			long seconds2 = millis / 1000;
			long hours = millis / (1000 * 60 * 60);
			millis -= hours * 1000 * 60 * 60;
			long minutes = millis / (1000 * 60);
			millis -= minutes * 1000 * 60;
			long seconds = millis / 1000;
			String hoursString = "";
			String minutesString = "";
			String secondsString = seconds + "";
			String type = "seconds";
			if (minutes > 0) {
				minutesString = minutes + ":";
				type = "minutes";
			}
			if (hours > 0) {
				hoursString = hours + ":";
				type = "hours";
			}
			if (minutesString.length() == 1) {
				minutesString = "0" + minutesString;
			}
			if (hoursString.length() == 1) {
				hoursString = "0" + hoursString;
			}
			if (secondsString.length() == 1) {
				secondsString = "0" + secondsString;
			}
			int x = 18;
			int y = 18;
			g.setColor(BG);
			g.fill3DRect(14, 25, 210, 165, true);
			g.setColor(GREEN);
			g.drawString(
					getName() + " v" + getVersion() + " by " + getAuthor(), x,
					y += 20);
			g.drawString("Running for " + hoursString + minutesString
					+ secondsString + " " + type + ".", x, y += 20);
			g.setColor(RED);
			g.drawString("Spun "
					+ (stringsBanked + getInventoryCount(BOW_STRING_ID))
					+ " flax.", x, y += 20);
			if (seconds2 != 0) {
				g.drawString("Averaging "
						+ (stringsBanked + getInventoryCount(BOW_STRING_ID))
						* 3600 / seconds2 + " strings per hour.", x, y += 20);
			}

		}

	}

	public void setCameraRotation2(int degrees) {
		// Aftermath's note:
		// This improved version presses other left OR right depending on which
		// direction the new angle is in
		// This is less botty than always rotating in the same direction no
		// matter which is closer
		char left = 37;
		char right = 39;
		char whichDir = left;
		int start = getCameraAngle();

		/*
		 * Some of this shit could be simplified, but it's easier to wrap my
		 * mind around it this way
		 */
		if (start < 180) {
			start += 360;
		}
		if (degrees < 180) {
			degrees += 360;
		}

		if (degrees > start) {
			if (degrees - 180 < start) {
				whichDir = right;
			}
		} else if (start > degrees) {
			if (start - 180 >= degrees) {
				whichDir = right;
			}
		}
		degrees %= 360;

		Bot.getInputManager().pressKey(whichDir);
		int timeWaited = 0;

		while (getCameraAngle() > degrees + 5 || getCameraAngle() < degrees - 5) {
			wait(10);
			timeWaited += 10;
			if (timeWaited > 500) {
				int time = timeWaited - 500;

				if (time == 0) {
					Bot.getInputManager().pressKey(whichDir);
				} else if (time % 40 == 0) {
					Bot.getInputManager().pressKey(whichDir);
				}
			}
		}
		Bot.getInputManager().releaseKey(whichDir);
	}

	public RSTile[] generatePath(RSTile tile) {
		return generatePath(tile.getX(), tile.getY());
	}

	public RSTile[] generatePath(int destinationX, int destinationY) { // credits
		// to
		// aftermath
		int startX = getMyPlayer().getLocation().getX();
		int startY = getMyPlayer().getLocation().getY();
		double dx, dy;
		ArrayList<RSTile> list = new ArrayList<RSTile>();

		list.add(new RSTile(startX, startY));
		while (Math.hypot(destinationY - startY, destinationX - startX) > 8) {
			dx = destinationX - startX;
			dy = destinationY - startY;
			int gamble = random(14, 17);
			while (Math.hypot(dx, dy) > gamble) {
				dx *= .95;
				dy *= .95;
			}
			startX += (int) dx;
			startY += (int) dy;
			list.add(new RSTile(startX, startY));
		}
		list.add(new RSTile(destinationX, destinationY));
		return list.toArray(new RSTile[list.size()]);

	}
}
